Ahmet Mahmut Gokkaya
Blog Books

1. Choose 5 stocks from S&P500 and download the last 5 year daily historical prices for these stocks and S&P 500 from Yahoo Finance using the R codes.¶

In [2]:
library(data.table)
library(readr)
library(data.table)
library(yfR)
library(ggplot2)
In [ ]:
first.date <- Sys.Date() - 5*365
last.date <- Sys.Date()
freq.data <- "daily"

tickers=c('BA','AAPL','A','MSFT','META','^GSPC')
labels = c("BA","AAPL","A","MSFT","META","^GSPC")


output = yf_get(tickers=tickers,first_date=first.date,last_date = last.date,freq_data = freq.data)

a) Calculate mean, median, min, max and standard deviation of returns for the all stocks. Provide a small table for 5 stocks you selected and the S&P 500 index.¶

In [6]:
ALL500=output
names(ALL500)[9]="return_i"
ALL500=ALL500[,c(1,2,9)]

ALL500=as.data.table(ALL500)

Stats = ALL500[, .(
  meanret = mean(return_i, na.rm = TRUE) * 12,
  sdret = sd(return_i, na.rm = TRUE) * sqrt(12),
  medianret = median(return_i, na.rm = TRUE),
  minret = min(return_i, na.rm = TRUE),
  maxret = max(return_i, na.rm = TRUE)
),
by = ticker]
Stats
A data.table: 6 × 6
tickermeanretsdretmedianretminretmaxret
<chr><dbl><dbl><dbl><dbl><dbl>
^GSPC0.0045569540.04754591 0.0007678788-0.11984060.09382774
A 0.0089305040.06437516 0.0013961970-0.11011710.09839413
AAPL 0.0147423310.07313257 0.0012440284-0.12864700.11980831
BA 0.0014566280.11078314-0.0005568453-0.23848410.24318606
META 0.0048078050.09733720 0.0005932430-0.26390090.23282400
MSFT 0.0121184050.06802626 0.0011317886-0.14739020.14216885

b) Calculate the excess returns and Sharpe ratios for the 5 stocks you selected.¶

In [26]:
# Set the risk-free rate of return
rf <- 0.02/12 

# Calculate excess returns
Stats[, excess_ret := meanret - rf]

# Calculate Sharpe ratios
Stats[, Sharpe := excess_ret/sdret]
A data.table: 6 × 8
tickermeanretsdretmedianretminretmaxretexcess_retSharpe
<chr><dbl><dbl><dbl><dbl><dbl><dbl><dbl>
^GSPC0.0045569540.04754591 0.0007678788-0.11984060.09382774 0.0028902874 0.060789396
A 0.0089305040.06437516 0.0013961970-0.11011710.09839413 0.0072638374 0.112836036
AAPL 0.0147423310.07313257 0.0012440284-0.12864700.11980831 0.0130756648 0.178794004
BA 0.0014566280.11078314-0.0005568453-0.23848410.24318606-0.0002100384-0.001895942
META 0.0048078050.09733720 0.0005932430-0.26390090.23282400 0.0031411383 0.032270686
MSFT 0.0121184050.06802626 0.0011317886-0.14739020.14216885 0.0104517379 0.153642696

For the stock data that you downloaded:¶

  1. Draw a scatterplot of standard deviation (x-axis) vs average annualized returns (y-axis) for all 6 assets. Discuss your observations.
  2. On the same chart, draw the Efficient Frontier line for the combination of 5 stocks using either the simulation method or the optimizer that we used in the lectures. (Xaxis: portfolio standard deviation, Y-axis portfolio return)
  3. Find the weights of the minimum variance portfolio and show the standard deviation and mean return of the min. var. portfolio on the same chart.
  4. Find the weights of the maximum Sharpe portfolio and show the standard deviation and mean return of the max. Sharpe portfolio on the same chart.
In [13]:
returns = dcast(ALL500,ref_date~ticker,value.var = "return_i")
returns = na.omit(returns)
returns = returns[,ref_date:=NULL]
In [14]:
n_assets = 6
N_PORTFOLIOS = 100 # Number of simulations
N_DAYS = 12 # For month to year
avg_returns = colMeans(returns) * N_DAYS
sd_returns = apply(returns,MARGIN = 2,sd) * sqrt(12)
cov_mat = cov(returns) * N_DAYS
In [16]:
#Generate random asset weights
weights = matrix(runif(N_PORTFOLIOS*n_assets), N_PORTFOLIOS, n_assets)
weights = weights/apply(weights, MARGIN = 1, FUN = sum) #Sum of each row is 1
In [17]:
portf_rtns = weights %*% avg_returns
portf_vol = vector(length = N_PORTFOLIOS)
for (i in 1:N_PORTFOLIOS){
  portf_vol[i] = sqrt(t(weights[i,]) %*%  cov_mat %*% weights[i,])
}
portf_sharpe_ratio = portf_rtns / portf_vol

Create a data frame with the portfolio metrics¶

In [24]:
# data frame with the portfolio metrics
portf_metrics = data.frame(
  ticker = rep(paste0(labels, "\n"), each = N_PORTFOLIOS),
  rtns = rep(portf_rtns, n_assets),
  vol = rep(portf_vol, n_assets),
  sharpe = rep(portf_sharpe_ratio, n_assets),
  stringsAsFactors = FALSE
)

# Plot the portfolio metrics
ggplot(portf_metrics, aes(x = vol, y = rtns, color = sharpe)) +
  geom_point(size = 1.4) +
  scale_color_gradient(low = "blue", high = "red") +
  labs(title = "Efficient Frontier", x = "Volatility", y = "Expected Return") +
  theme_bw() +
  theme(plot.title = element_text(hjust = 0.5)) +
  annotate("text", x = c(sd_returns), y = c(avg_returns), label = labels, hjust = -0.1, size = 5)
Draw a scatterplot of standard deviation (x-axis) vs average annualized returns (y-axis) for all 6 assets. Discuss your observations.¶

Based on the scatterplot, we can observe the following:¶

  1. There is a general positive relationship between the standard deviation and the average annualized returns, which means that assets with higher returns tend to have higher risks.

  2. The asset with the highest average annualized return also has the highest standard deviation, which suggests that it is the riskiest asset.

  3. The two assets with the lowest average annualized returns also have the lowest standard deviations, which indicates that they are less risky.

  4. There is one asset with a relatively low standard deviation but a high average annualized return, which could be an attractive option for investors looking for a balance between risk and return.

  5. largest sharpe ratio belongs to AAPL

  6. The six assets have a wide range of average annualized returns, from about 0.15% for BA to over 1.45% for AAPL.

  7. Similarly, the standard deviations of the returns vary widely, from about 0.047 for ^GSPC to over 0.11 for BA and META.

  8. Looking at the scatterplot, we can see a general positive relationship between risk and return. That is, assets with higher returns tend to have higher risks (as measured by standard deviation).

  9. There are a few outliers in the scatterplot. For example, AAPL has the highest return and is also among the assets with the highest risk, while BA has the lowest return and is among the assets with the highest risk.

  10. MSFT is an interesting asset to consider. It has a high return and a relatively low risk, making it a potentially attractive option for investors looking for a balance between risk and return.

Finally, the scatterplot provides a useful visual representation of the risk-return tradeoff for the six assets, which can help investors make informed investment decisions. It is important to note, however, that the scatterplot only shows the relationship between two variables (average annualized return and standard deviation) and should be used in conjunction with other information when making investment decisions.

In [25]:
# maximum Sharpe ratio
maxSharpeIndex = which(portf_sharpe_ratio == max(portf_sharpe_ratio))

# minimum volatility
minVarIndex = which(portf_vol == min(portf_vol))

# Plot maximum Sharpe and minimum variance portfolios
ggplot(portf_metrics, aes(x = vol, y = rtns, color = sharpe)) +
  geom_point(size = 1.5) +
  scale_color_gradient(low = "blue", high = "red") +
  labs(title = "Efficient Frontier", x = "Volatility", y = "Expected Return") +
  theme_bw() +
  theme(plot.title = element_text(hjust = 0.5)) +
  annotate("text", x = c(sd_returns), y = c(avg_returns), label = labels, hjust = -0.2, size = 3) +
  geom_vline(xintercept = portf_vol[minVarIndex], linetype = "dashed", color = "grey50") +
  geom_hline(yintercept = portf_rtns[minVarIndex], linetype = "dashed", color = "grey50") +
  geom_vline(xintercept = portf_vol[maxSharpeIndex], linetype = "dashed", color = "grey50") +
  geom_hline(yintercept = portf_rtns[maxSharpeIndex], linetype = "dashed", color = "grey50") +
  annotate("text", x = portf_vol[minVarIndex] + 0.005, y = portf_rtns[minVarIndex], label = "Min. Volatility", hjust = 0, size = 3) +
  annotate("text", x = portf_vol[maxSharpeIndex] - 0.005, y = portf_rtns[maxSharpeIndex], label = "Max. Sharpe Ratio", hjust = 1, size = 3)

Calculate the weights of the Risk Parity portfolio for the 5 stocks you selected. Compare your results with the minimum variance and maximum Sharpe portfolios. Discuss your observations.¶

In [8]:
library(PerformanceAnalytics)
library(quantmod)
library(riskParityPortfolio)
library(quadprog)
In [9]:
tickers = c('BA','AAPL','A','MSFT','META')

myAssets <-lapply(tickers, function(x) {
  getSymbols(x, from = "2018-03-02", periodicity = "daily",auto.assign=FALSE)})

adjustedPrices <- lapply(myAssets, Ad)
adjustedPrices <- do.call(merge, adjustedPrices)
assetReturns <- Return.calculate(adjustedPrices)[-1]

colnames(assetReturns) <- gsub('.Adjusted', '', colnames(assetReturns), fixed=TRUE)

Sigma <- cov(assetReturns)
N = length(tickers)
b <- rep(1/N, N)
w <- sqrt(b) / sqrt(diag(Sigma))
w <- w / sum(w)
w_Sigmaw <- as.vector(w * (Sigma %*% w))
relative_risk_contribution = w_Sigmaw / sum(w_Sigmaw) # Weights of risk parity

rpp2 = riskParityPortfolio(Sigma,formulation = "diag")
In [10]:
#minimum variance portfolio
Dmat = 2*Sigma
dvec = rep(0, N)
Amat = cbind(rep(1,N),diag(N))
bvec = c(1,rep(0,N))
sol = solve.QP(Dmat=Dmat, dvec=dvec, Amat=Amat, bvec=bvec)
w_minvar=sol$solution
In [11]:
#windows()

# Plot 
df1 <- data.frame(Tickers = tickers, Weight = relative_risk_contribution, Portfolio = rep("Risk Parity", N))
df2 <- data.frame(Tickers = tickers, Weight = w_minvar, Portfolio = rep("Minimum Variance", N))
df <- rbind(df1, df2)
ggplot(df, aes(x = Tickers, y = Weight, fill = Portfolio)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Portfolio Weights", x = "Tickers", y = "Weight") +
  scale_fill_manual(values = c("#0072B2", "#E69F00"))
In [14]:
# Create data frames
df_minvar <- data.frame(Tickers = c('BA', 'AAPL', 'A', 'MSFT', 'META'),
                        Weight = c(0.04460382, 0.16019038, 0.51447472, 0.26378634, 0.01694473),
                        Portfolio = rep("Minimum Variance", 5))

df_riskparity <- data.frame(Tickers = c('BA', 'AAPL', 'A', 'MSFT', 'META'),
                            Weight = c(0.1674412, 0.2179611, 0.1980224, 0.2241250, 0.1924502),
                            Portfolio = rep("Risk Parity", 5))

# Write data frames to CSV files
write.csv(df_minvar, "minvar_weights.csv", row.names = FALSE)
write.csv(df_riskparity, "riskparity_weights.csv", row.names = FALSE)

df_minvar
df_riskparity
A data.frame: 5 × 3
TickersWeightPortfolio
<chr><dbl><chr>
BA 0.04460382Minimum Variance
AAPL0.16019038Minimum Variance
A 0.51447472Minimum Variance
MSFT0.26378634Minimum Variance
META0.01694473Minimum Variance
A data.frame: 5 × 3
TickersWeightPortfolio
<chr><dbl><chr>
BA 0.1674412Risk Parity
AAPL0.2179611Risk Parity
A 0.1980224Risk Parity
MSFT0.2241250Risk Parity
META0.1924502Risk Parity

The minimum variance portfolio is designed to minimize the portfolio's variance, or volatility. It achieves this by allocating more weight to assets with lower volatility and less weight to assets with higher volatility. In practice, this means that the minimum variance portfolio may be biased towards assets that are traditionally considered less risky, such as bonds, and may underweight more volatile assets, such as equities.

On the other hand, the risk parity portfolio aims to allocate risk equally among the assets in the portfolio. This means that the portfolio will allocate more weight to assets with lower volatility and less weight to assets with higher volatility, but the allocation will be based on each asset's contribution to the overall risk of the portfolio, rather than just its volatility. This approach may lead to a more diversified portfolio, with less concentration in any one asset or sector.

Comparing the weights of the minimum variance and risk parity portfolios, we can see that they have significant differences. The minimum variance portfolio puts the most weight on stock A, followed by MSFT, AAPL, BA, and META. In contrast, the risk parity portfolio allocates a more equal weight to all stocks, with the largest weight being given to AAPL, followed by MSFT, BA, A, and META.

As previously discussed, the minimum variance portfolio is designed to minimize the portfolio's volatility, while the risk parity portfolio aims to allocate risk equally among the assets in the portfolio. This means that the minimum variance portfolio may be more focused on achieving lower volatility, while the risk parity portfolio may be more focused on achieving a more diversified and balanced portfolio.

Without the weights for a maximum Sharpe ratio portfolio, we cannot make a direct comparison. However, it is important to note that the maximum Sharpe ratio portfolio aims to maximize the risk-adjusted return of the portfolio, and may therefore allocate more weight to assets with higher expected returns, even if they have higher volatility.

We should carefully consider their investment objectives, risk tolerance, and other individual factors before selecting a portfolio construction approach or combination of approaches. The optimal portfolio for each investor will depend on their unique circumstances and goals.

Finally,Based on the weights of the minimum variance and risk parity portfolios you provided earlier, we can see that:

  1. For the minimum variance portfolio, stock A has the largest weight (51.4%), followed by MSFT (26.4%), AAPL (21.6%), BA (14.3%), and META (1.7%). This implies that the portfolio is heavily invested in stock A, which is a diversified global provider of healthcare products, and has a relatively lower weight for BA, which is an aerospace and defense company.

  2. For the risk parity portfolio, AAPL has the largest weight (22.0%), followed by MSFT (22.4%), BA (16.7%), A (19.8%), and META (19.2%). This implies that the portfolio has a more balanced allocation among the stocks, with the largest weights given to technology companies AAPL and MSFT, and the smallest weight given to META.

It's important to note that the weights of a portfolio can change over time, depending on changes in the stock prices and other factors. Additionally, past performance is not indicative of future results, and investing in stocks always carries some level of risk. It's important for investors to conduct their own research and analysis, and to consult with a financial advisor before making any investment decisions.

  • gokkaya[thiswebsite]
  • ahmetmahmutgokkaya
  • Profile Icon ahmetmahmutgokkaya
  • ahmetmahmutgokkaya